#pragma once

#include <optional>

#include <boost/program_options.hpp>

#include "util/fs.h"


class CmdOptions {
public:
	CmdOptions(int argc, char *argv[]);

	bool needHelp() const;

	void printHelp(std::ostream &stream);

	class Option {
	public:
		Option(const std::string &longName, const std::string &desc)
			: longName_(longName), desc_(desc) {}

		Option(const std::string &longName, char shortName, const std::string &desc)
			: longName_(longName), shortName_(shortName), desc_(desc) {}

		const std::string &longName() const {
			return longName_;
		}

		std::string mkBoostOptName() const {
			std::string s;
			s.append(longName_);
			if (shortName_) {
				s.push_back(',');
				s.push_back(*shortName_);
			}
			return s;
		}

		const std::string &desc() const {
			return desc_;
		}

	private:
		std::string longName_;
		std::optional<char> shortName_;
		std::string desc_;
	};

private:

	class OptionsDescEasyInit {
	public:
		OptionsDescEasyInit(boost::program_options::options_description_easy_init &ref)
			: ref_(ref) {}

		void operator()(const std::string &name, const std::string &description) {
			ref_(name.c_str(), description.c_str());
		}

		void operator()(const Option &option) {
			(*this)(option.mkBoostOptName(), option.desc());
		}

	private:
		boost::program_options::options_description_easy_init &ref_;
	};

	void addOptions(OptionsDescEasyInit &add);

	std::string valueOfLogLevel() const;

private:
	fs::path exe_;
	boost::program_options::options_description desc_{ "Options" };
	boost::program_options::positional_options_description posdesc_;
	boost::program_options::variables_map varmap_;
};
